﻿#include "SnapImgView.h"
#include <QDateTime>
#include <QWheelEvent>
#include <QLayoutItem>
#include <QGridLayout>
#include <QDebug>
#include <QApplication>

namespace OfUI {

	SnapImgView::SnapImgView(QWidget *parent)
		:QWidget(parent)
	{
		init();
		setGroupType(GroupType::DAY);
		setShowItemPath(true);
	}

	SnapImgView::~SnapImgView()
	{
		clearItemCache();
	}

	void SnapImgView::setItemDelegate(SnapImgItemDelegate* pDelegate)
	{
		if (pDelegate)
		{
			if (m_pSnapItemDelegate)
			{
				m_pSnapItemDelegate->deleteLater();
			}
			m_pSnapItemDelegate = pDelegate;
			m_pSnapItemDelegate->setParent(this);
		}
	}

	SnapImgItemDelegate* SnapImgView::getItemDelegate()
	{
		return m_pSnapItemDelegate;
	}

	void SnapImgView::setGroupType(const GroupType& eType)
	{
		m_eGroupType = eType;
		if (GroupType::DAY == m_eGroupType)
		{
			m_strDateTimeFmt = "yyyy/MM/dd";
		}
		else if (GroupType::MONTH == m_eGroupType)
		{
			m_strDateTimeFmt = "yyyy/MM";
		}
		else if (GroupType::YEAR == m_eGroupType)
		{
			m_strDateTimeFmt = "yyyy";
		}
	}

	GroupType SnapImgView::getGroupType() const
	{
		return m_eGroupType;
	}

	void SnapImgView::setShowItemPath(bool bShow)
	{
		m_bShowItemPath = bShow;

		for (auto pItem : findChildren<SnapImgItem*>())
		{
			pItem->setItemShowBottom(m_bShowItemPath);
		}
	}

	bool SnapImgView::isShowItemPath() const
	{
		return m_bShowItemPath;
	}

	QList<SnapDataGroup> SnapImgView::spiltDataToGroup(const QList<SnapData>& srcDataList)
	{
		QList<SnapDataGroup> groupList;

		for (const SnapData& data : srcDataList)
		{
			QString strDateTime = QDateTime::fromTime_t(data.m_nSnapTime).toString(m_strDateTimeFmt);
			quint64 nGroupTime = QDateTime::fromString(strDateTime, m_strDateTimeFmt).toTime_t();

			SnapDataGroup newGroup;
			newGroup.m_nGroupTime = nGroupTime;
			newGroup.m_nDataCount = 1;
			newGroup.m_dataList << data;
			int nIndex = groupList.indexOf(newGroup);

			if (-1 == nIndex)
			{
				groupList << newGroup;
			}
			else
			{
				groupList[nIndex].m_nDataCount++;
				groupList[nIndex].m_dataList << data;
			}
		}
		return groupList;
	}

	void SnapImgView::updateSnapData(const QList<SnapData>& dataList)
	{
		QList<SnapDataGroup> groupList = spiltDataToGroup(dataList);
		updateSnapDataGroup(groupList);
	}

	void SnapImgView::updateSnapDataGroup(const QList<SnapDataGroup>& list)
	{
		QList<SnapDataGroup> groupList = list;
		// 当前组过多，删除部分组
		QLayoutItem* child;
		while (m_pVLayout->count() > groupList.count())
		{
			SnapGroupView* pGroupView = static_cast<SnapGroupView*>(m_pVLayout->itemAt(0)->widget());
			if (pGroupView)
			{
				while (pGroupView->getCount() > 0)
				{
					pushItemToCache(pGroupView->takeItemByIndex(0));
				}
			}

			if (child = m_pVLayout->takeAt(0))
			{
				if (child->widget())
				{
					child->widget()->setParent(nullptr);
					child->widget()->deleteLater();
				}
				delete child;
			}
		}
		// 当前组过少， 添加部分组
		while (m_pVLayout->count() < groupList.count())
		{
			m_pVLayout->addWidget(createSnapGroupView());
		}

		// 重置原先选择列表Item状态
		resetSelectState();
		// 刷新数据时，清空上次的选择
		m_selectedItemsData.clear();

		// 对组进行按时间排序
		qSort(groupList.begin(), groupList.end(), sortSnapDataGroupByTime);

		for (int i = 0; i < groupList.count() && i < m_pVLayout->count(); ++i)
		{
			SnapGroupView* pGroupView = dynamic_cast<SnapGroupView*>(m_pVLayout->itemAt(i)->widget());
			if (pGroupView)
			{
				SnapDataGroup group = groupList.at(i);
				QList<SnapData> groupData = groupList[i].m_dataList;

				// 当前Item过多，删除部分
				while (groupData.count() < pGroupView->getCount())
				{
					SnapImgItem* pItem = pGroupView->takeItemByIndex(0);
					pushItemToCache(pItem);
				}
				// 当前Item过少，添加部分
				while (groupData.count() > pGroupView->getCount())
				{
					SnapImgItem* pItem = pullItemFromCache();
					pGroupView->addItem(pItem);
				}
				pGroupView->setGroup(group, m_pSnapItemDelegate->getItemGroupTitle(group, m_eGroupType));
			}
		}

		// Item数据刷新后，再设置之前选择的Item状态
		updateSelectState();
	}

	void SnapImgView::insertSnapData(const QList<SnapData>& dataList)
	{
		QList<SnapDataGroup> groupList = spiltDataToGroup(dataList);
		insertSnapDataGroup(groupList);
	}

	void SnapImgView::insertSnapDataGroup(const QList<SnapDataGroup>& list)
	{
		QList<SnapDataGroup> groupList = list;
		// 重置原先选择列表Item状态
		resetSelectState();

		for (auto& group : groupList)
		{
			quint64 nGroupTime = group.m_nGroupTime;
			quint64 nGroupDataCount = group.m_nDataCount;

			// 判断当前 nGroupTime 对应组是否已经存在，是则插入数据，否则创建新组，再在新组插入数据
			SnapGroupView* pGroupView = findGroupViewByTime(nGroupTime);

			if (pGroupView)
			{
				// 将新插入的组数据与旧组数据重组
				for (auto& data : pGroupView->getGroup().m_dataList)
				{
					if (-1 == group.m_dataList.indexOf(data))
					{
						group.m_dataList.append(data);
						nGroupDataCount++;
					}
				}
			}
			else
			{
				SnapGroupView* pNewGroupView = createSnapGroupView();
				int nInsertPos = 0;

				for (int i = 0; i < m_pVLayout->count(); i++)
				{
					SnapGroupView* pExistGroupView = dynamic_cast<SnapGroupView*>(m_pVLayout->itemAt(i)->widget());
					// 已创建的 Group 排序自上而下时间递减
					if (pExistGroupView && nGroupTime >= pExistGroupView->getGroup().m_nGroupTime)
					{
						break;
					}
					nInsertPos++;
				}
				m_pVLayout->insertWidget(nInsertPos, pNewGroupView);
				pGroupView = pNewGroupView;
			}

			// 当前Item过多，删除部分
			while (group.m_dataList.count() < pGroupView->getCount())
			{
				SnapImgItem* pItem = pGroupView->takeItemByIndex(0);
				pushItemToCache(pItem);
			}
			// 当前Item过少，添加部分
			while (group.m_dataList.count() > pGroupView->getCount())
			{
				SnapImgItem* pItem = pullItemFromCache();
				pGroupView->addItem(pItem);
			}
			pGroupView->setGroup(group, m_pSnapItemDelegate->getItemGroupTitle(group, m_eGroupType));
		}

		// Item数据刷新后，再设置之前选择的Item状态
		updateSelectState();
	}

	void SnapImgView::deleteSnapDataById(const int& nId)
	{
		for (int i = 0; i < m_pVLayout->count(); i++)
		{
			SnapGroupView* pGroupView = static_cast<SnapGroupView*>(m_pVLayout->itemAt(i)->widget());
			if (pGroupView && pGroupView->findItemById(nId))
			{
				SnapImgItem* pItem = pGroupView->takeItemById(nId);
				SnapData data = pItem->getData();
				pushItemToCache(pItem);

				if (pItem->isSelected())
				{
					deleteFromSelectList(nId);
				}

				// 更新组标题
				SnapDataGroup group = pGroupView->getGroup();
				group.m_dataList.removeOne(data);
				group.m_nDataCount--;
				pGroupView->setGroup(group, m_pSnapItemDelegate->getItemGroupTitle(group, m_eGroupType));

				// 若该组没有了 Item，则删除该组
				if (pGroupView->getCount() <= 0)
				{
					QLayoutItem* pChild = m_pVLayout->takeAt(i);
					if (pChild && pChild->widget())
					{
						pChild->widget()->setParent(nullptr);
						pChild->widget()->deleteLater();
						delete pChild;
					}
				}
				break;
			}
		}
	}

	bool SnapImgView::replaceOneSnapData(const SnapData& oldData, const SnapData& newData)
	{
		bool nRet = false;
		bool bSampleId = oldData.m_nId == newData.m_nId;

		if (bSampleId)
		{
			SnapImgItem* pItem = findSnapItemById(oldData.m_nId);
			if (pItem)
			{
				pItem->setData(newData);
				nRet = true;
			}
		}
		else
		{
			SnapImgItem* pOldItem = findSnapItemById(oldData.m_nId);
			SnapImgItem* pNewItem = findSnapItemById(newData.m_nId);

			if (pOldItem && !pNewItem)
			{
				pOldItem->setData(newData);
				nRet = true;
			}
		}
		return nRet;
	}

	const QList<SnapData>& SnapImgView::getSelectData() const
	{
		return m_selectedItemsData;
	}

	void SnapImgView::setSelectData(const QList<SnapData>& selectList)
	{
		resetSelectState();
		m_selectedItemsData.clear();
		m_selectedItemsData.append(selectList);
		updateSelectState();
	}

	void SnapImgView::setSelectData(const SnapData& selectData)
	{
		resetSelectState();
		m_selectedItemsData.clear();
		m_selectedItemsData.append(selectData);
		updateSelectState();
	}

	void SnapImgView::setMaxZoomLimit(float fRatio)
	{
		if (fRatio >= 1.0 && fRatio <= 2.0)
		{
			m_fMaxZoomLimit = fRatio;

			while (m_fCurrentZoom > m_fMaxZoomLimit)
			{
				setItemZoomOut();
			}
		}
	}

	float SnapImgView::getMaxZoomLimit() const
	{
		return m_fMaxZoomLimit;
	}

	void SnapImgView::setMinZoomLimit(float fRatio)
	{
		if (fRatio >= 0.1 && fRatio <= 1.0)
		{
			m_fMinZoomLimit = fRatio;

			while (m_fCurrentZoom < m_fMinZoomLimit)
			{
				setItemZoomIn();
			}
		}
	}

	float SnapImgView::getMinZoomLimit() const
	{
		return m_fMinZoomLimit;
	}

	void SnapImgView::setScrollBarValue(int nValue)
	{
		m_pScrollArea->verticalScrollBar()->setValue(nValue);
	}

	QList<SnapData> SnapImgView::getAllSnapData()
	{
		QList<SnapData> dataList;
		for (int i = 0; i < m_pVLayout->count(); i++)
		{
			SnapGroupView* pGroupView = static_cast<SnapGroupView*>(m_pVLayout->itemAt(i)->widget());
			if (pGroupView)
			{
				dataList.append(pGroupView->getGroup().m_dataList);
			}
		}
		return dataList;
	}

	bool SnapImgView::eventFilter(QObject *watched, QEvent *event)
	{
		if (watched == m_pScrollAreaWidgetContents)
		{
			if (QEvent::Wheel == event->type())
			{
				// Ctrl + 鼠标滚轮 控制放大缩小
				if (Qt::ControlModifier == QApplication::keyboardModifiers())
				{
					QWheelEvent* pWheelEvt = static_cast<QWheelEvent*>(event);

					if (pWheelEvt->delta() > 0)
					{
						// 设置Item 放大
						this->setItemZoomIn();
					}
					else
					{
						// 设置Item 缩小
						this->setItemZoomOut();
					}
					event->accept();
					return true;
				}
			}
			else if (QEvent::KeyPress == event->type())
			{
				QKeyEvent* pKeyEvent = static_cast<QKeyEvent*>(event);

				if (Qt::Key_Up == pKeyEvent->key() || Qt::Key_Down == pKeyEvent->key() ||
					Qt::Key_Left == pKeyEvent->key() || Qt::Key_Right == pKeyEvent->key())
				{
					// Shift + 键盘上下左右 多选
					if (Qt::ShiftModifier == QApplication::keyboardModifiers())
					{
						event->accept();
						return true;
					}
				}
			}
		}

		return QObject::eventFilter(watched, event);
	}

	void SnapImgView::resizeEvent(QResizeEvent *event)
	{
		Q_UNUSED(event);
	}

	void SnapImgView::init()
	{
		creatUI();

		m_fMinZoomLimit = 0.6;
		m_fMaxZoomLimit = 2.0;
		m_fCurrentZoom = 1.0;
		m_fZoomSpeed = 0.1;

		m_pSnapItemDelegate = nullptr;
		setItemDelegate(new SnapImgItemDelegate);
		m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
		m_pScrollArea->verticalScrollBar()->setContextMenuPolicy(Qt::NoContextMenu);
		m_pScrollAreaWidgetContents->installEventFilter(this);

		// 滚动条变化响应
		connect(m_pScrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this, [this](int nValue)
		{
			int nMinimum = m_pScrollArea->verticalScrollBar()->minimum();
			int nMaximum = m_pScrollArea->verticalScrollBar()->maximum();
			emit signalScrollBarValueChanged(nValue, nMinimum, nMaximum);
		});
	}

	void SnapImgView::creatUI()
	{
		this->setObjectName("SnapImgView");

		// 创建滚动区域
		m_pScrollArea = new QScrollArea(this);
		m_pScrollArea->setWidgetResizable(true);

		m_pScrollAreaWidgetContents = new QWidget();
		m_pScrollAreaWidgetContents->setObjectName("scrollAreaContent");
		m_pScrollArea->setWidget(m_pScrollAreaWidgetContents);

		m_pVLayout = new QVBoxLayout();
		m_pVLayout->setMargin(0);
		m_pVLayout->setSpacing(10);

		QVBoxLayout *pScrollLayout = new QVBoxLayout(m_pScrollAreaWidgetContents);
		pScrollLayout->setMargin(0);
		pScrollLayout->setSpacing(0);
		pScrollLayout->addLayout(m_pVLayout);
		pScrollLayout->addStretch(1);

		// 整体布局
		QVBoxLayout *pMainLayout = new QVBoxLayout(this);
		pMainLayout->setMargin(0);
		pMainLayout->setSpacing(0);
		pMainLayout->addWidget(m_pScrollArea);

	}

	void SnapImgView::resetSelectState()
	{
		for (auto iter = m_selectedItemsData.begin(); iter != m_selectedItemsData.end();)
		{
			SnapImgItem* pFindItem = findSnapItemById(iter->m_nId);
			if (pFindItem)
			{
				pFindItem->setSelect(false);
			}
			iter++;
		}
	}

	void SnapImgView::updateSelectState()
	{
		//bool bSelectChanged = false;
		for (auto iter = m_selectedItemsData.begin(); iter != m_selectedItemsData.end();)
		{
			SnapImgItem* pFindItem = findSnapItemById(iter->m_nId);
			if (pFindItem)
			{
				pFindItem->setSelect(true);
				*iter = pFindItem->getData();
				iter++;
			}
			else
			{
				// 删除掉目前不显示的选择项
				//bSelectChanged = true;
				iter = m_selectedItemsData.erase(iter);
			}
		}
	}

	SnapGroupView* SnapImgView::createSnapGroupView()
	{
		SnapGroupView* pGroupView = new SnapGroupView;
		return pGroupView;
	}

	SnapGroupView* SnapImgView::findGroupViewByTime(const quint64& nTime)
	{
		SnapGroupView* pFindGroupView = nullptr;
		for (int i = 0; i < m_pVLayout->count(); i++)
		{
			SnapGroupView* pGroupView = static_cast<SnapGroupView*>(m_pVLayout->itemAt(i)->widget());
			if (pGroupView && nTime == pGroupView->getGroup().m_nGroupTime)
			{
				pFindGroupView = pGroupView;
				break;
			}
		}
		return pFindGroupView;
	}

	SnapImgItem* SnapImgView::findSnapItemById(const int& nId)
	{
		SnapImgItem* pFindItem = nullptr;
		QList<SnapImgItem*> itemList = findChildren<SnapImgItem*>();

		for (auto pItem : itemList)
		{
			if (nId == pItem->getData().m_nId)
			{
				pFindItem = pItem;
				break;
			}
		}
		return pFindItem;
	}

	void SnapImgView::appendToSelelctList(const SnapData& data)
	{
		for (auto iter = m_selectedItemsData.begin(); iter != m_selectedItemsData.end(); iter++)
		{
			if (iter->m_nId == data.m_nId)
			{
				m_selectedItemsData.erase(iter);
				break;
			}
		}
		m_selectedItemsData.push_back(data);
	}

	bool SnapImgView::deleteFromSelectList(const int& nId)
	{
		bool bDelOk = false;
		for (auto iter = m_selectedItemsData.begin(); iter != m_selectedItemsData.end(); iter++)
		{
			if (iter->m_nId == nId)
			{
				m_selectedItemsData.erase(iter);
				bDelOk = true;
				break;
			}
		}
		return bDelOk;
	}

	void SnapImgView::pushItemToCache(SnapImgItem* pItem)
	{
		if (pItem && (-1 == m_cacheItemList.indexOf(pItem)))
		{
			disconnect(pItem, 0, 0, 0);
			m_cacheItemList.append(pItem);
		}
	}

	SnapImgItem* SnapImgView::pullItemFromCache()
	{
		SnapImgItem* pItem = nullptr;
		if (m_cacheItemList.size() > 0)
		{
			pItem = m_cacheItemList.at(0);
			m_cacheItemList.pop_front();
		}
		else
		{
			// 通过委托创建 Item
			pItem = m_pSnapItemDelegate->createEditor();
		}

		Q_ASSERT(pItem);

		pItem->initForm();
		pItem->setSelect(false);
		pItem->setItemShowBottom(m_bShowItemPath);
		pItem->setZoom(m_fCurrentZoom);
		pItem->setSnapImgViewPointer(this);

		// Item选中状态改变响应
		connect(pItem, &SnapImgItem::signalItemSelectChanged, this, [this](const SnapData& data, bool bSelect, bool bSingleSelect)
		{
			if (bSelect)
			{
				if (bSingleSelect)
				{
					resetSelectState();
					m_selectedItemsData.clear();
				}

				appendToSelelctList(data);
				updateSelectState();
			}
			else
			{
				deleteFromSelectList(data.m_nId);
			}

			// 通知外层选中Item组变化了
			emit signalItemSelectsChanged(m_selectedItemsData);
		}, Qt::UniqueConnection);

		// Item 右键菜单响应
		connect(pItem, &SnapImgItem::signalItemContextMenu, this, [this](const SnapData& data, QPoint globalPos)
		{
			emit signalItemContextMenu(data, globalPos);
		}, Qt::UniqueConnection);

		// Item 自定义消息响应
		connect(pItem, &SnapImgItem::signalItemCustomMsg, this, &SnapImgView::signalItemCustomMsg, Qt::UniqueConnection);
		return pItem;
	}

	void SnapImgView::clearItemCache()
	{
		while (m_cacheItemList.count() > 0)
		{
			m_cacheItemList.at(0)->deleteLater();
			m_cacheItemList.removeAt(0);
		}
	}

	void SnapImgView::setItemZoomIn()
	{
		// 放大操作
		if (m_fCurrentZoom + m_fZoomSpeed > m_fMaxZoomLimit)
		{
			return;
		}
		m_fCurrentZoom += m_fZoomSpeed;

		QList<SnapImgItem*> itemList = this->findChildren<SnapImgItem*>();
		for (auto& pItem : itemList)
		{
			pItem->setZoom(m_fCurrentZoom);
		}
	}

	void SnapImgView::setItemZoomOut()
	{
		// 缩小操作
		if (m_fCurrentZoom - m_fZoomSpeed < m_fMinZoomLimit)
		{
			return;
		}
		m_fCurrentZoom -= m_fZoomSpeed;

		QList<SnapImgItem*> itemList = this->findChildren<SnapImgItem*>();
		for (auto& pItem : itemList)
		{
			pItem->setZoom(m_fCurrentZoom);
		}
	}

}
